/**
  *****************************************************************************
  * @file 
  * @brief 
  * @author  
  * @version
  * @date    2021/07/31
  *****************************************************************************
  */
/* Includes -----------------------------------------------------------------*/
#include "task_gnss.h"
#include "task_lvgl.h"

#include "sportstate.h"

#include "hal_uart.h"

//#include "notify.h"
#include "minmea.h"

#include "lvgl_module.h"
#include "at32f403a_407_board.h"

#include <string.h>

/* Private defines ----------------------------------------------------------*/

#ifdef 	GNSS_TASK_DEBUG_MODE
#define gps_task_hal_err(...)               do{dbg_printf(__VA_ARGS__);dbg_printf("\r\n");}while(0)
#define gps_task_hal_info(...)              do{dbg_printf(__VA_ARGS__);dbg_printf("\r\n");}while(0)
#define gps_task_hal_debug(...)             do{dbg_printf(__VA_ARGS__);dbg_printf("\r\n");}while(0)
#else
#define gps_task_hal_err(...)               do{dbg_printf(__VA_ARGS__);dbg_printf("\r\n");}while(0)
#define gps_task_hal_info(...)              do{dbg_printf(__VA_ARGS__);dbg_printf("\r\n");}while(0)
#define gps_task_hal_debug(...)
#endif

/* Private Struct -----------------------------------------------------------*/

struct nmea_s{
		enum minmea_sentence_id type;
    void *data;
};
/* Publick Variable -------------------------------------------------------------*/
TaskHandle_t app_gnss_handler;
/* Private Variable ---------------------------------------------------------*/
 QueueHandle_t gnss_evt_q = NULL;
/* 软件定时器句柄 */
static TimerHandle_t gnss_evt_t = NULL;   
/* gps接收数据相关变量 */
static uint8_t gps_receive_buf[GPS_REC_BUF_SIZE] = {0};
static uint16_t gps_receive_len = 0;
/* 本地记录当前解析gps数据 */
static gps_info_t gps_local_info = {0};
/* 本地记录当前sport_state数据 */
static sport_status_info_t  sport_local_status_info = {0};

/* Private function prototypes ----------------------------------------------*/
static void gnss_receive_irq_callback(void);
static void sport_status_update_callback(void* parameter);
static void dev_gnss_init(void);

/*****************************************************************************
* @brief  初始化
* ex:
* @par
* None
* @retval
*****************************************************************************/
static void dev_gnss_init(void)
{
	usart_config_t usart_cfg;
	/* 串口 */
	usart_cfg.rx_dma_en = 1;
	usart_cfg.baud_rate = 9600;
	usart_cfg.data_bits = USART_DATA_8BITS;
	usart_cfg.flowcontrol = USART_HARDWARE_FLOW_NONE;
	usart_cfg.parity = USART_PARITY_NONE;
	usart_cfg.rxbuf_size = GPS_REC_BUF_SIZE;
	usart_cfg.stop_bits = USART_STOP_1_BIT;
	
	hal_usart_rxirq_connect(USART2, gnss_receive_irq_callback);
	hal_usart_init(USART2, &usart_cfg);
}

void gps_signal_init(void)
{
		gnss_evt_q = xQueueCreate(TASK_MSG_QUEUE_COUNT, sizeof(EVENT_T));
		if (gnss_evt_q == NULL)
		{
				/* 没有创建成功,加入创建失败的处理机制 */
		}
}

static void gnss_event_init(void)
{		
		gnss_evt_t = xTimerCreate((const char*		)"sport_status_update_callback",
														 (TickType_t			)500,/* 定时器周期 500(tick) */
														 (UBaseType_t		)pdTRUE,/* 周期模式 */
														 (void*				  )1,/* 为每个计时器分配一个索引的唯一ID */
														 (TimerCallbackFunction_t)sport_status_update_callback); 
		if(gnss_evt_t == NULL)
		{
				/* 没有创建成功,加入创建失败的处理机制 */
		}
}

BaseType_t gnss_evt_message_send(EVENT_T* event, TickType_t wait_tick)
{
		portBASE_TYPE taskWoken = pdFALSE;
	
		if (__get_IPSR()) 
		{
			 if (xQueueSendFromISR(gnss_evt_q, event, &taskWoken) != pdTRUE) 
			 {
					return pdFALSE;
			 }
			 
			 portEND_SWITCHING_ISR(taskWoken);
		}
		else 
		{
			if (xQueueSend(gnss_evt_q, event, wait_tick) != pdTRUE) 
			{
				return pdFALSE;
			}
		}
		
		return pdTRUE;
}


BaseType_t gnss_evt_message_get(EVENT_T* event, TickType_t wait_tick){
		portBASE_TYPE taskWoken = pdFALSE;
		
		if (__get_IPSR()) 
		{
				if (xQueueReceiveFromISR(gnss_evt_q, event, &taskWoken) == pdTRUE) 
				{
						portEND_SWITCHING_ISR(taskWoken);
				}
		}
		else
		{
				return xQueueReceive(gnss_evt_q, event, wait_tick);
		}
		
		return pdTRUE;
}


static struct nmea_s* nema_parse(const char *sentence, uint8_t strict)
{
	
		struct nmea_s * nmea = NULL;
	  enum minmea_sentence_id  type = MINMEA_INVALID;
	
		nmea = pvPortMalloc(sizeof(struct nmea_s));
		if(nmea == NULL)
		{
			gps_task_hal_debug("nmea malloc error.");
			return NULL;
		}
		gps_task_hal_debug("nmea = %x.", nmea);
		memset(nmea, 0, sizeof(struct nmea_s));
		
		type = minmea_sentence_id(sentence, strict);
		nmea->type = type;
		gps_task_hal_debug("nmea->type = %d.", nmea->type);
		gps_task_hal_debug("nmea->data = %x.", nmea->data);
	
		switch (type) 
		{
				case MINMEA_SENTENCE_RMC: 
						{
								struct minmea_sentence_rmc *frame = pvPortMalloc(sizeof(struct minmea_sentence_rmc));
								if (frame == NULL)
								{
										gps_task_hal_debug("frame malloc error.");
										goto _error;
								}
								
								gps_task_hal_debug("frame = %x.", frame);
								
								if (minmea_parse_rmc(frame, sentence)) 
								{
										nmea->data = frame;
										gps_task_hal_debug("nmea->data = %x.", nmea->data);
								}
								else 
								{
										gps_task_hal_debug("$xxRMC sentence is not parsed\n");
										goto _error;
								}
						} 
					break;
				case MINMEA_SENTENCE_GGA: 
						{
								struct minmea_sentence_gga *frame = pvPortMalloc(sizeof(struct minmea_sentence_gga));
								if (frame == NULL)
								{
										gps_task_hal_debug("frame malloc error.");
										goto _error;
								}
								
								if (minmea_parse_gga(frame, sentence)) 
								{
										nmea->data = frame;
								}
								else 
								{
										gps_task_hal_debug("$xxGGA sentence is not parsed");
										goto _error;
								}
						} 
					break;
				case MINMEA_SENTENCE_GST: 
						{
								struct minmea_sentence_gst *frame = pvPortMalloc(sizeof(struct minmea_sentence_gst));
								if (frame == NULL)
								{
										gps_task_hal_debug("frame malloc error.");
										goto _error;
								}
							
								if (minmea_parse_gst(frame, sentence)) 
								{
										nmea->data = frame;
								}
								else 
								{
										gps_task_hal_debug("$xxGST sentence is not parsed");
										goto _error;
								}
						} 
				  break;
				case MINMEA_SENTENCE_GSV: 
						{
								struct minmea_sentence_gsv *frame = pvPortMalloc(sizeof(struct minmea_sentence_gsv));
								if (frame == NULL)
								{
										gps_task_hal_debug("frame malloc error.");
										goto _error;
								}
								
								if (minmea_parse_gsv(frame, sentence)) 
								{
										nmea->data = frame;
								}
								else 
								{
										gps_task_hal_debug("$xxGSV sentence is not parsed");
										goto _error;
								}
						} 
					break;
				case MINMEA_SENTENCE_VTG: 
						{
								struct minmea_sentence_vtg *frame = pvPortMalloc(sizeof(struct minmea_sentence_vtg));
								if (frame == NULL)
								{
										gps_task_hal_debug("frame malloc error.");
										goto _error;
								}
								
								if (minmea_parse_vtg(frame, sentence)) 
								{
									nmea->data = frame;
								}
								else
								{
										gps_task_hal_debug("$xxVTG sentence is not parsed");
										goto _error;
								}
						 } 
					break;
			  case MINMEA_SENTENCE_ZDA: 
						{
								struct minmea_sentence_zda *frame = pvPortMalloc(sizeof(struct minmea_sentence_zda));
								if (frame == NULL)
								{
										gps_task_hal_debug("frame malloc error.");
										goto _error;
								}
								
								if (minmea_parse_zda(frame, sentence)) 
								{
										nmea->data = frame;
								}
								else 
								{
									  gps_task_hal_debug("$xxZDA sentence is not parsed");
										goto _error;
								}
						} 
					break;	
				case MINMEA_INVALID: 
						{
								gps_task_hal_debug("sentence is invalid");
								goto _error;
						} 
					break;
					default: 
						{
								//gps_task_hal_debug("default");
								goto _error;
						}
					break;			
		}
		
		return nmea;
_error:
	if(nmea)
	{
		if(nmea->data)
		{
			vPortFree(nmea->data);
		}
		vPortFree(nmea);
		nmea = NULL;
	}
	return NULL;
}


static int nmea_value_update(struct nmea_s *nmea, gps_info_t *gps_data)
{
//    int i;
    struct minmea_sentence_rmc *rmc = NULL;
    struct minmea_sentence_gsv *gsv = NULL;
    struct minmea_sentence_gga *gga = NULL;
    struct minmea_sentence_gsa *gsa = NULL;

    if(nmea == NULL || gps_data == NULL)
    {
        gps_task_hal_debug("param invalid.");
			
        return -1;
    }
    if(nmea->type == MINMEA_UNKNOWN)
    {
        gps_task_hal_debug("gps nmea type is unknown!");
			
        return -1;
    }
		gps_task_hal_debug("gps nmea type %d", nmea->type);
    switch(nmea->type)
    {
        case MINMEA_SENTENCE_RMC:
            rmc = (struct minmea_sentence_rmc*)nmea->data;
            if(rmc)
            {
                gps_data->isVaild = rmc->valid;
								gps_data->latitude = minmea_tocoord(&rmc->latitude);
								gps_data->longitude = minmea_tocoord(&rmc->longitude);
							  gps_data->speed = minmea_tofloat(&rmc->speed);
								gps_data->clock.day = rmc->date.day;
								gps_data->clock.month = rmc->date.month;
								gps_data->clock.year = rmc->date.year;
								gps_data->clock.hour = rmc->time.hours;
								gps_data->clock.minute = rmc->time.minutes;
								gps_data->clock.second = rmc->time.seconds;
								gps_data->clock.millisecond = 0;
								gps_data->course = minmea_tofloat(&rmc->course);
								gps_data->clock.week = 0;
            }
        break;
        case MINMEA_SENTENCE_GSV:
            gsv = (struct minmea_sentence_gsv*)nmea->data;
            if(gsv)
            {
								
            }
        break;
        case MINMEA_SENTENCE_GGA:
            gga = (struct minmea_sentence_gga*)nmea->data;
            if(gga != NULL)
            {
							gps_data->altitude = minmea_tofloat(&gga->altitude);
							gps_data->satellites = gga->satellites_tracked;
            }
        break;
        case MINMEA_SENTENCE_GSA:
            gsa = (struct minmea_sentence_gsa*)nmea->data;
            if(gsa != NULL)
            {
							
            }
        break;
        default: break;
    }
    return 0;
}

/*****************************************************************************
* @brief  
* ex:
* @par
* None
* @retval
*****************************************************************************/
void task_gnss(void *arg)
{
	EVENT_T info;
	struct nmea_s *nmea = NULL;

	dev_gnss_init();
	gnss_event_init();
	/* 开启定时器 */	
	xTimerStart(gnss_evt_t,0);	
  while (1)
  {	
		if (pdTRUE == gnss_evt_message_get(&info, portMAX_DELAY))
		{
				switch(info.evt_id)
				{
					case GNSS_EVT_NEMA:
						//strcpy((char*)gps_receive_buf,"$GPRMC,081836.75,A,3751.65,S,14507.36,E,021.1,360.0,130998,011.3,E");
						gps_task_hal_debug("GNSS_EVT_NEMA");
						nmea = nema_parse((char *)gps_receive_buf, 0);
						if (nmea)
						{		
								int ret = nmea_value_update(nmea, &gps_local_info);
							 	if(ret)
								{
										gps_task_hal_debug("nmea_value_update error.");
								}
								if (nmea->data) 
								{
										vPortFree(nmea->data);
										nmea->data = NULL;
								}
								vPortFree(nmea);
								nmea = NULL; 
								
								//gps_task_hal_debug("gps_local_info.speed = %f",gps_local_info.speed);
								/* 将数据发送到各个注册中的任务 */
								notifier_call_chain(notify_gps_list, &gps_local_info, sizeof(gps_local_info));
						}
						break;
					case GNSS_EVT_SPORT_STATE:
						{
								gps_task_hal_debug("GNSS_EVT_SPORT_STATE");
								sport_local_status_info = sport_status_update(&gps_local_info);
							
								EVENT_T lv_info;
							
								sport_status_info_t* sport_status_info = (sport_status_info_t*)pvPortMalloc(sizeof(sport_status_info_t));
								memset(sport_status_info, 0, sizeof(sport_status_info_t));
							
								memcpy(sport_status_info, &sport_local_status_info, sizeof(sport_status_info_t));
										
								lv_info.evt_id = LVGL_EVT_SHOW;
								lv_info.param1 = LVGL_EVT_SHOW_SPORT;
								lv_info.param2 = (uint32_t)sport_status_info;
								if (pdTRUE != lv_evt_message_send(LVGL_EVT_SHOW, &lv_info, TASK_MSG_PUT_TIMEOUT))
								{
										/* send failed */
										gps_task_hal_debug("sport_status_info send error.");
										vPortFree(sport_status_info);
								}
						}
						break;
				
					default: break;
				}
		}
  }
}



/*****************************************************************************
* @brief  串口回调函数
* ex:
* @par
* None
* @retval
*****************************************************************************/
static void gnss_receive_irq_callback(void)
{
		EVENT_T info;
	
		memset(gps_receive_buf, 0, GPS_REC_BUF_SIZE);
		gps_receive_len = hal_usart_read(USART2, gps_receive_buf, GPS_REC_BUF_SIZE);

		info.evt_id = GNSS_EVT_NEMA;
		if (pdTRUE != gnss_evt_message_send(&info, TASK_MSG_PUT_TIMEOUT))
		{
			/* send failed */
		}
}

/*****************************************************************************
* @brief  定时器回调函数
* ex:
* @par
* None
* @retval
*****************************************************************************/
static void sport_status_update_callback(void* parameter)
{		
		EVENT_T info;
	
		info.evt_id = GNSS_EVT_SPORT_STATE;
		//info.evt_id = GNSS_EVT_NEMA; /* test */
		if (pdTRUE != gnss_evt_message_send(&info, TASK_MSG_PUT_TIMEOUT))
		{
			/* send failed */
		}
}
